/**
 * @file base_file_parser.c
 * @brief 基准文件解析模块实现
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "base_file_parser.h"
#include "score_engine.h"
#include "log.h"
// 添加打印宏，方便添加前缀
//#define BFP_PRINT(fmt, ...) printf("BaseFileParser: " fmt, ##__VA_ARGS__)
//#define BFP_ERROR(fmt, ...) fprintf(stderr, "BaseFileParser-ERROR: " fmt, ##__VA_ARGS__)

// Simple checksum calculation function
uint16_t calculate_checksum(const void* data, size_t size) {
    const uint8_t* bytes = (const uint8_t*)data;
    uint32_t sum = 0;
    
    // Calculate checksum by processing two bytes at a time as 16-bit unsigned integers
    for (size_t i = 0; i < size; i += 2) {
        uint16_t value;
        
        if (i + 1 < size) {
            // Two bytes available, combine as big-endian 16-bit value
            value = (bytes[i] << 8) | bytes[i+1];
        } else {
            // Last byte, left-shift by 8
            value = (bytes[i] << 8);
        }
        
        sum += value;
    }
    
    // Keep result within 16-bit range
    return (uint16_t)(sum & 0xFFFF);
}

// Verify file checksum
int verify_file_checksum(const BaseFileHeader* header, const void* data, size_t data_size) {
    // Skip checksum validation if checksum is 0 (might not be calculated)
    if (header->checksum == 0) {
        BFP_PRINT("Warning: File checksum is 0, skipping checksum verification\n");
        return 1;
    }
    
    // Calculate checksum only for frame data, skip header
    uint16_t calculated_sum = calculate_checksum(data, data_size);
    
    // Compare with stored checksum
    if (calculated_sum != header->checksum) {
        BFP_PRINT("Error: Checksum mismatch. Stored: 0x%04X, Calculated: 0x%04X\n", 
                 header->checksum, calculated_sum);
        return 0;
    }
    
    BFP_PRINT("Checksum verification passed\n");
    return 1;
}

// Print base file header information
void print_base_file_header(const BaseFileHeader* header) {
    BFP_PRINT("Base File Header Information:\n");
    BFP_PRINT("  Magic: %.4s\n", header->magic);
    BFP_PRINT("  Version: %d.%d\n", (header->version >> 8) & 0xFF, header->version & 0xFF);
    BFP_PRINT("  Song ID: %.64s\n", header->song_id);
    BFP_PRINT("  Total Frames: %u\n", header->total_frames);
    BFP_PRINT("  Sample Rate: %u Hz\n", header->sample_rate);
    BFP_PRINT("  Frame Size: %u samples\n", header->frame_size);
    BFP_PRINT("  Hop Size: %u samples\n", header->hop_size);
    BFP_PRINT("  Precision: %u\n", header->precision & 0xFF);
    BFP_PRINT("  Features Flag: 0x%04X\n", header->features_flag);
    BFP_PRINT("  Checksum: 0x%04X\n", header->checksum);
    BFP_PRINT("  Num Sentences: %u\n", header->num_sentences);

    // Print available features
    BFP_PRINT("  Available Features: ");
    if (header->features_flag & FEATURE_PITCH) BFP_PRINT("Pitch ");
    if (header->features_flag & FEATURE_TIMBRE) BFP_PRINT("Timbre ");
    if (header->features_flag & FEATURE_RHYTHM) BFP_PRINT("Rhythm ");
    if (header->features_flag & FEATURE_ENERGY) BFP_PRINT("Energy ");
    if (header->features_flag & FEATURE_BRIGHTNESS) BFP_PRINT("Brightness ");
    if (header->features_flag & FEATURE_SPECTRUM) BFP_PRINT("Spectrum ");
    if (header->features_flag == 0) BFP_PRINT("None");
    BFP_PRINT("\n");
}

// Validate base file header
int validate_base_file_header(const BaseFileHeader* header, int expected_sample_rate, int expected_frame_size) {
    // Check magic number
    if (memcmp(header->magic, "VBAS", 4) != 0) {
        BFP_PRINT("Error: Invalid file magic number (%.4s), expected 'VBAS'\n", header->magic);
        return ERROR_FILE_CORRUPT;
    }
    
    // Check version (support version 0.x and 1.x)
    uint8_t major_version = (header->version >> 8) & 0xFF;
    uint8_t minor_version = header->version & 0xFF;
    BFP_PRINT("Detected file version: %d.%d\n", major_version, minor_version);
    
    if (major_version > 1) {
        BFP_PRINT("Error: Unsupported file version %d.%d (supported: 0.x and 1.x)\n", 
                 major_version, minor_version);
        return ERROR_FILE_VERSION_MISMATCH;
    }
    
    // Verify sample rate if specified
    if (expected_sample_rate > 0 && header->sample_rate != (uint32_t)expected_sample_rate) {
        BFP_PRINT("Error: Sample rate mismatch. File: %u Hz, Expected: %d Hz\n", 
                 header->sample_rate, expected_sample_rate);
        return ERROR_SAMPLE_RATE_MISMATCH;
    }
    
    // Verify frame size if specified - now expected_frame_size is half frame size
    if (expected_frame_size > 0 && header->frame_size != (uint16_t)(expected_frame_size * 2)) {
        BFP_PRINT("Error: Frame size mismatch. File: %u samples, Expected: %d samples (from half frame size %d)\n", 
                 header->frame_size, expected_frame_size * 2, expected_frame_size);
        return ERROR_FRAME_SIZE_MISMATCH;
    }
    
    // Check for required features
    uint16_t required_features = FEATURE_PITCH | FEATURE_RHYTHM;  // At minimum require pitch and rhythm
    
    /*
    // 对于0.x版本文件，跳过特征检查
    if (major_version == 0) {
        BFP_PRINT("Version 0.x detected, skipping feature requirements check\n");
    } else if ((header->features_flag & required_features) != required_features) {
        BFP_PRINT("Error: Base file is missing required features\n");
        BFP_PRINT("Required features: Pitch, Rhythm\n");
        return ERROR_FILE_CORRUPT;
    }
    */
    BFP_PRINT("Feature check is temporarily disabled\n");
    
    // Basic sanity checks
    if (header->total_frames == 0) {
        BFP_PRINT("Warning: File contains zero frames\n");
    }
    
    if (header->frame_size == 0 || header->sample_rate == 0) {
        BFP_PRINT("Error: Invalid frame size or sample rate\n");
        return ERROR_CONFIG_INVALID;
    }
    
    // Check for valid hop_size (should be <= frame_size)
    if (header->hop_size > header->frame_size) {
        BFP_PRINT("Error: Invalid hop size (%u) - larger than frame size (%u)\n", 
                 header->hop_size, header->frame_size);
        return ERROR_CONFIG_INVALID;
    }
    
    return ERROR_SUCCESS;
}

// 从文件路径加载基准文件
int load_base_file(const char* file_path, BaseFileHeader* header_out, void** data_out, size_t* data_size_out) {
    if (!file_path || !header_out || !data_out || !data_size_out) {
        return ERROR_CONFIG_INVALID;
    }

    // 打开文件
    FILE* fp = fopen(file_path, "rb");
    if (!fp) {
        BFP_PRINT("Error: Cannot open file: %s\n", file_path);
        return ERROR_FILE_NOT_FOUND;
    }

    // 读取文件头部 (128 bytes)
    BaseFileHeader file_header;
    size_t header_read = fread(&file_header, sizeof(BaseFileHeader), 1, fp);
    if (header_read != 1) {
        fclose(fp);
        BFP_PRINT("Error: Failed to read file header\n");
        return ERROR_FILE_CORRUPT;
    }

    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    size_t file_size = ftell(fp);
    fseek(fp, sizeof(BaseFileHeader), SEEK_SET);  // 从头部后开始读取数据

    // 计算数据大小
    size_t data_size = file_size - sizeof(BaseFileHeader);

    // 分配内存并读取文件内容
    void* file_data = malloc(data_size);
    if (!file_data) {
        fclose(fp);
        BFP_PRINT("Error: Out of memory\n");
        return ERROR_OUT_OF_MEMORY;
    }

    // 读取文件数据部分
    size_t read_bytes = fread(file_data, 1, data_size, fp);
    fclose(fp);

    if (read_bytes != data_size) {
        free(file_data);
        BFP_PRINT("Error: Failed to read file data\n");
        return ERROR_FILE_CORRUPT;
    }

    // 输出结果
    *header_out = file_header;
    *data_out = file_data;
    *data_size_out = data_size;

    return ERROR_SUCCESS;
}


// 从内存数据加载基准文件
int load_base_file_data(const void* data_buffer, size_t buffer_size, BaseFileHeader* header_out, void** data_out, size_t* data_size_out) {
    if (!data_buffer || buffer_size == 0 || !header_out || !data_out || !data_size_out) {
        return ERROR_CONFIG_INVALID;
    }

    // 检查缓冲区大小是否足够容纳头部
    if (buffer_size < sizeof(BaseFileHeader)) {
        BFP_ERROR("Error: Buffer too small for header\n");
        return ERROR_FILE_CORRUPT;
    }

    // 读取文件头部
    memcpy(header_out, data_buffer, sizeof(BaseFileHeader));

    // 计算数据大小
    size_t data_size = buffer_size - sizeof(BaseFileHeader);

    // 分配内存并复制数据
    void* file_data = malloc(data_size);
    if (!file_data) {
        BFP_ERROR("Error: Out of memory\n");
        return ERROR_OUT_OF_MEMORY;
    }

    // 复制数据部分
    memcpy(file_data, (char*)data_buffer + sizeof(BaseFileHeader), data_size);

    // 输出结果
    *data_out = file_data;
    *data_size_out = data_size;

    return ERROR_SUCCESS;
}
